package com.mars.web.common.exception;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.fastjson.JSON;
import com.mars.common.exception.BizException;
import com.mars.common.utils.WebUtil;

//@ControllerAdvice(annotations=Controller.class)
public class ExceptionAdvice {

	private static Logger logger = LoggerFactory.getLogger(ExceptionAdvice.class);

	/**
	 * 400 - Bad Request
	 */
	/*@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler(HttpMessageNotReadableException.class)
	public ResponseResult handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
		logger.error("参数解析失败", e);
		return ResponseResult.error("参数解析失败");
	}*/

	/**
	 * 405 - Method Not Allowed
	 */
	/*@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public ResponseResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
		logger.error("不支持当前请求方法", e);
		return ResponseResult.error("不支持当前请求方法");
	}*/

	/**
	 * 415 - Unsupported Media Type
	 */
	/*@ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
	@ExceptionHandler(HttpMediaTypeNotSupportedException.class)
	public ResponseResult handleHttpMediaTypeNotSupportedException(Exception e) {
		logger.error("不支持当前媒体类型", e);
		return ResponseResult.error("不支持当前媒体类型");
	}*/

	/**
	 * 统一异常处理
	 */
	@ExceptionHandler(Exception.class)
	public ModelAndView handleException(Exception e, HttpServletRequest request, HttpServletResponse response) {
		logger.error("Web统一异常处理", e);
		String requestType = request.getHeader("X-Requested-With");
		Map<String, Object> map = new HashMap<String, Object>();

		if (!"XMLHttpRequest".equals(requestType)) {// 非Ajax请求
			ModelAndView mv = new ModelAndView();
			map.put("request", WebUtil.getCurrentUrl(request, true));

			if (e instanceof BizException) {
				mv.setViewName("common/exception/500");
				mv.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
				map.put("status", mv.getStatus().value());
				map.put("message", e.getMessage());
				mv.addAllObjects(map);
			} else if (e instanceof RpcException) {
				mv.setViewName("common/exception/500");
				mv.setStatus(HttpStatus.SERVICE_UNAVAILABLE);
				map.put("status", mv.getStatus().value());
				map.put("message", "Dubbo分布式服务不可用<br>" + e.getMessage());

				mv.addAllObjects(map);
			} else {
				mv.setViewName("common/exception/500");
				mv.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
				map.put("status", mv.getStatus().value());
				map.put("message", e.getMessage());
				mv.addAllObjects(map);
			}
			return mv;

		} else {
			response.setContentType("application/json;charset=utf-8");
			PrintWriter out = null;
			try {
				out = response.getWriter();
				if (e instanceof BizException) {
					response.setStatus(500);
					map.put("status", response.getStatus());
					map.put("message", e.getMessage());
					map.put("request", WebUtil.getCurrentUrl(request, true));
					out.print(JSON.toJSONString(map));
				} else if (e instanceof RpcException) {
					response.setStatus(503);
					map.put("status", response.getStatus());
					map.put("message", "Dubbo分布式服务不可用<br>" + e.getMessage());
					map.put("request", WebUtil.getCurrentUrl(request, true));
					out.print(JSON.toJSONString(map));
				} else {
					response.setStatus(500);
					map.put("status", response.getStatus());
					map.put("message", e.getMessage());
					map.put("request", WebUtil.getCurrentUrl(request, true));
					out.print(JSON.toJSONString(map));
				}

			} catch (IOException ioEx) {
				ioEx.printStackTrace();
			} finally {
				out.flush();
				out.close();
			}
			return null;
		}
	}

}
